#pragma once
#include "ListIterator.hpp"
#include "collection/Collection.hpp"
#include "lang/Exception.h"
#include "yzrutil.h"
#include "lang/String.h"
#include <initializer_list>

namespace yzrilyzr_collection{
	template<typename E>
	ECLASS(List, public Collection<E>){
	public:
	virtual ~List()=default;
	u_index modCount=0;
	List(){}
	bool add(const E & e)override{
		add(this->size(), e);
		return true;
	}
	virtual E get(u_index index) const=0;

	virtual E set(u_index index, const E & element)=0;

	virtual void add(u_index index, const E & element)=0;

	virtual E remove(u_index index)=0;

	void rangeCheckForAdd(u_index index) const{
		if(index < 0 || index > this->size())
			throw yzrilyzr_lang::IndexOutOfBoundsException(outOfBoundsMsg(index));
	}

	yzrilyzr_lang::String outOfBoundsMsg(u_index index) const{
		return yzrilyzr_lang::String("Index: ") << index << ", Size: " << this->size();
	}

	virtual u_index indexOf(const E & o) const{
		auto itp=constListIterator();
		while(itp->hasNext())
			if(o == itp->next())
				return itp->previousIndex();
		return -1;
	}

	virtual int32_t hashCode() const override{
		int32_t hashCode=1;
		for(E & e : *this)
			hashCode=31 * hashCode + yzrilyzr_lang::ObjectUtil::hashCode(e);
		return hashCode;
	}

	virtual u_index lastIndexOf(const E & o) const{
		auto itp=constListIterator(this->size());
		while(itp->hasPrevious())
			if(o == itp->previous())
				return itp->nextIndex();
		return -1;
	}

	virtual E & operator[](u_index index) const=0;

	virtual void clear() override{
		u_index fromIndex=0;
		u_index toIndex=this->size();
		auto itp=listIterator(fromIndex);
		for(u_index i=0, n=toIndex - fromIndex; i < n; i++){
			itp->next();
			itp->remove();
		}
	}
	virtual bool addAll(u_index index, const Collection<E> &c){
		rangeCheckForAdd(index);
		bool modified=false;
		for(E e:c){
			add(index++, e);
			modified=true;
		}
		return modified;
	}
	virtual bool addAll(const Collection<E> &c)override{
		return Collection<E>::addAll(c);
	}

	/*void insert(const E * pos, const E * begin, const E * end){
		u_index index=indexOf(pos);
		for(E * i=begin; i < end; i++){
			add(index, i);
		}
	}*/

	/*void erase(const E * begin, const E * end){}

	void assign(const E * begin, const E * end){}*/

	static void subListRangeCheck(u_index fromIndex, u_index toIndex, u_index size){
		if(fromIndex < 0)
			throw yzrilyzr_lang::IndexOutOfBoundsException(yzrilyzr_lang::String("fromIndex = ") + fromIndex);
		if(toIndex > size)
			throw yzrilyzr_lang::IndexOutOfBoundsException(yzrilyzr_lang::String("toIndex = ") + toIndex);
		if(fromIndex > toIndex)
			throw yzrilyzr_lang::IllegalArgumentException(
				yzrilyzr_lang::String("fromIndex(") << fromIndex << ") > toIndex(" << toIndex << ")");
	}
	ECLASS(Itr, public virtual Iterator<E>){
	protected:
	u_index cursor=0;
	u_index lastRet=-1;
	u_index expectedModCount;
	const List * clist=nullptr;
	List * list=nullptr;
	public:
	explicit Itr(const List * clist, List * list) :clist(clist), list(list){
		expectedModCount=clist->modCount;
	}
	bool hasNext()const override{
		return cursor != clist->size();
	}

	E & next()override{
		checkForComodification();
		u_index i=cursor;
		E & next=(*clist)[i];
		lastRet=i;
		cursor=i + 1;
		return next;
	}

	void remove() override{
		if(lastRet < 0)
			throw yzrilyzr_lang::IllegalStateException();
		checkForComodification();
		list->remove(lastRet);
		if(lastRet < cursor)
			cursor--;
		lastRet=-1;
		expectedModCount=clist->modCount;
	}
	protected:
	void checkForComodification(){
		if(clist->modCount != expectedModCount)
			throw yzrilyzr_lang::ConcurrentModificationException();
	}
	};

	//template<typename E>
	ECLASS(ListItr, public Itr, public ListIterator<E>){
	public:
	ListItr(const List * clist, List * list, u_index index) : Itr(clist, list){
		this->cursor=index;
	}

	bool hasPrevious()const override{
		return this->cursor != 0;
	}

	E & previous()override{
		this->checkForComodification();
		u_index i=this->cursor - 1;
		E & previous1=(*this->clist)[i];
		this->lastRet=this->cursor=i;
		return previous1;
	}

	u_index nextIndex()const override{
		return this->cursor;
	}

	u_index previousIndex()const override{
		return this->cursor - 1;
	}

	void set(E & e) override{
		if(this->lastRet < 0)
			throw yzrilyzr_lang::IllegalStateException();
		this->checkForComodification();
		this->list->set(this->lastRet, e);
		this->expectedModCount=this->list->modCount;
	}

	void add(E & e) override{
		this->checkForComodification();
		u_index i=this->cursor;
		this->list->add(i, e);
		this->lastRet=-1;
		this->cursor=i + 1;
		this->expectedModCount=this->list->modCount;
	}
	};

	virtual std::unique_ptr<ListIterator<E>> listIterator(){
		return listIterator(0);
	}
	virtual std::unique_ptr<ListIterator<E>> constListIterator()const{
		return constListIterator(0);
	}
	std::unique_ptr<Iterator<E>> iterator() override{
		return std::make_unique<Itr>(this, this);
	}
	std::unique_ptr<Iterator<E>> constIterator()const override{
		return std::make_unique<Itr>(this, nullptr);
	}
	virtual std::unique_ptr<ListIterator<E>> listIterator(u_index index){
		rangeCheckForAdd(index);
		return std::make_unique<ListItr>(this, this, index);
	}
	virtual std::unique_ptr<ListIterator<E>> constListIterator(u_index index)const{
		rangeCheckForAdd(index);
		return std::make_unique<ListItr>(this, nullptr, index);
	}
	/*virtual List<E> subList(u_index fromIndex, u_index toIndex){
		subListRangeCheck(fromIndex, toIndex, size());
		return SubList<>(this, fromIndex, toIndex);
	}*/
	};
}